Skip to content

feat(breaking): migrate Flow to TS; remove some deprecated functions and aliases #881

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 13 commits into from
Mar 25, 2022

Conversation

AugustinLF
Copy link
Collaborator

@AugustinLF AugustinLF commented Dec 6, 2021

This is the first draft of a PR to switch from flow to TS. The PR includes a green build for typescript and tests. It also includes the deletion of several deprecated APIs as discussed in #877.

There is still a bit left to do, but I'd like to have to have a 👍 before fixing those:

  • flow types (like we used to do with TS)
  • Build set up: I'm unsure what strategy we'd like to use to publish a typeless build + expose the TS types, if not I'll try to follow repack's one

Removed functionality:

  • deprecation messages for all fns deprecated in v2 (getByName, getByType, etc)
  • waitForElement
  • shallow
  • flushMicrotasksQueue

Closes #877

<TouchableOpacity
accessibilityHint={BUTTON_HINT}
accessibilityLabel={BUTTON_LABEL}
accessibilityRole="button"
// @ts-ignore - accessibilityStates removed in RN 0.62
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we consider dropping support for that? Just curious

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

maybe try accessibilityState={{ selected: true }}

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do support accessibilityState (see below for instance, my question is that since RN 0.62 doesn't support accessibilityStates anymore, should we support it? And if yes, for how long?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the oldest React-Native version mentioned in docs is >= 0.61 and I see no clear "minimum supported React Native version" info, I'd assume people can be using RNTL in 0.61~ versions where accessibilityStates prop is still around. Thus I'd keep it if it does not incur big maintenance cost.

expect(
disabledSelected && disabledSelected.props.accessibilityStates
).toEqual(['selected', 'disabled']);
expect(disabledSelected?.props.accessibilityStates).toEqual([
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It runs TS linter rules now, is it something we want? Perhaps we need to make sure that this doesn't have more impact (some JS rules disappearing, or something like that?)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it extends callstack ESLint preset I think it's more of a concern of @callstack/eslint-config to maintain parity between the two? I've quickly checked and I don't see glaring differences between JS/TS configs. @thymikee do you think it may be a problem?

/**
* Wait for microtasks queue to flush
*/
export default function flushMicrotasksQueue<T>(): Thenable<T> {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Deleted this one

findByLabelText: (string | RegExp, ?WaitForOptions) => FindReturn,
findAllByA11yLabel: (string | RegExp, ?WaitForOptions) => FindAllReturn,
findAllByLabelText: (string | RegExp, ?WaitForOptions) => FindAllReturn,
getByA11yLabel: (label: string | RegExp) => GetReturn;
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we consider deprecating the aliases?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I would keep them for the time being, as not all a11y queries have their RTL-like counterpart.
@thymikee wdyt?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my ideal world each query should exists only once (no alias) and have the same behaviour as on web. For instance, we could drop getByA11yLabel and keep getByLabelText, since this one is supported on both platforms.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's get rid of aliases for queries that are available on RTL, like ByLabelText for example. It's a simple search-replace change, so no biggie

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed the *LabelText and *Role aliases.

@@ -0,0 +1,17 @@
{
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copied from the repack one, adding jsx support

Copy link
Member

@mdjastrzebski mdjastrzebski left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Great work @AugustinLF! I strongly support moving from Flow to Typescript as a better and de-facto standard type-checking solution.

}
throw new ErrorWithStack(error.message, callsite);

throw new ErrorWithStack('Something wrong happened when querying', callsite);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider something along the lines:

Suggested change
throw new ErrorWithStack('Something wrong happened when querying', callsite);
throw new ErrorWithStack(`Query: caught unknown error type: ${typeof error}, value: ${error?.toString()}`, callsite);

@@ -23,7 +23,10 @@ const getTextInputNodeByDisplayValue = (
matches(value, nodeValue, normalizer, exact)
);
} catch (error) {
throw createLibraryNotSupportedError(error);
if (error instanceof Error) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should not silently ignore the non-Error values. It should be better to just analyse the error type inside the createLibraryNotSupportedError.

findByLabelText: (string | RegExp, ?WaitForOptions) => FindReturn,
findAllByA11yLabel: (string | RegExp, ?WaitForOptions) => FindAllReturn,
findAllByLabelText: (string | RegExp, ?WaitForOptions) => FindAllReturn,
getByA11yLabel: (label: string | RegExp) => GetReturn;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I would keep them for the time being, as not all a11y queries have their RTL-like counterpart.
@thymikee wdyt?

@@ -11,15 +10,15 @@ import {
within,
getQueriesForElement,
getDefaultNormalizer,
} from '../..';
} from '@testing-library/react-native';
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@thymikee you suggested to export flow types the same way we did with TS, but I can't get the import here to work (hence the red build), are you familiar with how to do that?

@AugustinLF AugustinLF force-pushed the convert-to-typescript branch from f99fddb to fa9a1c5 Compare January 12, 2022 14:48
@AugustinLF
Copy link
Collaborator Author

@thymikee I just rebased to fix the conflict, and I believe I addressed all the comments (only left one is mine #881 (comment) waiting for your input). Is there anything else you'd like me to do?

@thymikee
Copy link
Member

@AugustinLF I see that Flow check is failing, would be cool to remove it :) Other than that please just wait a bit more for me to find time and review this. Thanks so much for the work you've done already!

@AugustinLF
Copy link
Collaborator Author

Yeah, the issue with the flow check is that I don't know how to make it possible to "test" the flow types #881 (comment). If I remove the test file for the types the build pass, but then we have no guarantee that the flow types are correct.

Thanks for taking the time reviewing :)

expect(getAllByA11yLabel).toBe(getAllByLabelText);
expect(queryAllByA11yLabel).toBe(queryAllByLabelText);
expect(findAllByA11yLabel).toBe(findAllByLabelText);
});

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

While we may discuss about usefulness of this test, why it gets removed with this PR? :)

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This test just checks that aliases work and we removed them

#881 (comment)

import * as React from 'react';
import { Text } from 'react-native';
import ReactTestRenderer from 'react-test-renderer';
import act from '../act';
import render from '../render';
import fireEvent from '../fireEvent';

const UseEffect = ({ callback }: { callback: Function }) => {
type UseEffectProps = { callback: () => void };

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

small improvement (?):

Suggested change
type UseEffectProps = { callback: () => void };
type UseEffectProps = { callback(): void };

@@ -11,7 +10,7 @@ beforeAll(() => {

let isMounted = false;

class Test extends React.Component<*> {
class Test extends React.Component<any> {

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
class Test extends React.Component<any> {
class Test extends React.Component {

import * as React from 'react';
import { View } from 'react-native';
import { render } from '..';

let isMounted = false;

class Test extends React.Component<*> {
class Test extends React.Component<{ onUnmount?: () => void }> {
Copy link

@Killavus Killavus Jan 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you can also do the same treatment onUnmount?(): void or keep it as-is. Decision is yours, I find the latter a little bit easier to read.

@@ -146,7 +148,8 @@ describe('findBy options deprecations', () => {
});

test.skip('getByText works properly with custom text component', () => {
function BoldText({ children }) {
type BoldTextProps = { children: React.ReactNode };

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How about extracting this to higher scope:

type ChildrenProps = { children: React.ReactNode }

And then reuse for all tests expecting children?

export function flushMicroTasks<T>(): Thenable<T> {
return {
// using "thenable" instead of a Promise, because otherwise it breaks when
// using "modern" fake timers
Copy link

@Killavus Killavus Jan 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can you check if it's still the case with TypeScript bindings for jest (@types/jest)? Keeping this type may be not optimal if it's not needed.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's not a type issue (btw @types/jest are already installed), that comment/code was already there.

Looks mostly good to me. I'd definitely take a look whether we can get rid of Thenable in https://github.com/callstack/react-native-testing-library/pull/881/files#r792187961 flushMicroTasks after migration from Flow to TypeScript.

Sounds like a good plan to me.

value,
options?: TextMatchOptions = {}
node: ReactTestInstance,
value: string | RegExp,

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this particular union may deserve an alias because of its widespread use. WDYT @thymikee?

const getChildrenAsText = (children, TextComponent) => {
const textContent = [];
const getChildrenAsText = (
children: (string | number | React.ReactElement)[],

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
children: (string | number | React.ReactElement)[],
children: React.ReactChild[],

@@ -30,20 +28,21 @@ function getJestFakeTimersType() {
}

if (
// @ts-ignore jest mutates setTimeout
Copy link

@Killavus Killavus Jan 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it's a good place to use @ts-expect-error instead of @ts-ignore. We know that there'll be TS error here so no error is an undesired behavior as well.

src/waitFor.ts Outdated
await act(async () => {
result = await waitForInternal(expectation, optionsWithStackTrace);
});

//$FlowFixMe: either we have result or `waitFor` threw error
// @ts-ignore either we have result or `waitFor` threw error
return result;

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think you can use ! operator to force TS to trust you it's always valid. You can keep the comment though.

Copy link

@Killavus Killavus left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks mostly good to me. I'd definitely take a look whether we can get rid of Thenable in https://github.com/callstack/react-native-testing-library/pull/881/files#r792187961 flushMicroTasks after migration from Flow to TypeScript.

Also string | RegExp type may be aliased to something more in testing-library nomenclature. The rest of my comments are small stylistic improvements & small type improvements (like using React.ReactChild instead of enumerating possibilities, or restricting any in some places).

@AugustinLF AugustinLF force-pushed the convert-to-typescript branch from 8d9e4f3 to c5b2a22 Compare February 15, 2022 09:40
@AugustinLF
Copy link
Collaborator Author

@Killavus I should have addressed all your comments (or answered). I just let one hanging, waiting for a confirmation. Please let me know if you need anything else!

@AugustinLF
Copy link
Collaborator Author

@Killavus can I be of any help, or do anything to help getting that merged?

@AugustinLF AugustinLF changed the title [WIP] Port types to TS Port types to TS Mar 21, 2022
@thymikee thymikee changed the title Port types to TS feat(breaking): migrate Flow to TS; remove some deprecated functions and aliases Mar 24, 2022
Copy link
Member

@thymikee thymikee left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good and ready to be merged. However, since this is a breaking change, I wonder if we shouldn't tackle #934 first and release it in a minor release. WDYT?

@AugustinLF
Copy link
Collaborator Author

Sounds fair to me!

@thymikee
Copy link
Member

@AugustinLF v9.1.0 is released so let's rebase this and we can merge this work 🚀

@AugustinLF AugustinLF force-pushed the convert-to-typescript branch from a6a19fa to 3f53f1e Compare March 25, 2022 11:08
@AugustinLF
Copy link
Collaborator Author

@thymikee rebased. However CI didn't not thing to have been triggered, did you change anything recently?

@thymikee
Copy link
Member

@AugustinLF nothing else than merging a bunch of Dependabot PRs

@thymikee
Copy link
Member

There's some outage around self-hosted runners, may be related: https://status.circleci.com

@thymikee thymikee merged commit 1360b73 into callstack:main Mar 25, 2022
@thymikee
Copy link
Member

Thank you @AugustinLF!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Native TS support
5 participants